package services

import (
	"context"
	"errors"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"gorm.io/gen"
	"gorm.io/gen/field"
	"gorm.io/gorm"
	"mall_frontend_api/biz/config"
	"mall_frontend_api/biz/dal"
	"mall_frontend_api/biz/handler/base"
	"mall_frontend_api/biz/model"
	"mall_frontend_api/biz/model/cart"
	"mall_frontend_api/biz/pack"
	"mall_frontend_api/biz/util"
)

type CartService struct {
	ctx    context.Context
	common *base.Response
	dao    *dal.InitDAO
}

func NewCartService(ctx context.Context, common *base.Response) *CartService {
	return &CartService{ctx: ctx, common: common, dao: dal.NewInitDAO()}
}

func (c *CartService) GetCartList(req *cart.GetCartListRequest) ([]*cart.Cart, int64, error) {
	list, total, err := c.dao.CartDAO.GetListWithTotal(c.ctx, &dal.CartListParams{
		Condition: []gen.Condition{
			dal.Cart.UserID.Eq(c.common.GetUserInfo().ID),
		},
		Page: c.common.GetPage(),
		Size: c.common.GetSize(),
		Sort: []field.Expr{dal.Cart.CreatedAt.Desc()},
	})
	if err != nil {
		hlog.CtxErrorf(c.ctx, "GetCartList error: %v", err)
		return nil, 0, err
	}
	var productIDs []int64
	for _, m := range list {
		productIDs = append(productIDs, m.ProductID)
	}
	productMap, err := c.dao.ProductDAO.MGet(c.ctx, util.Unique(productIDs))
	if err != nil {
		hlog.CtxErrorf(c.ctx, "GetProduct error: %v", err)
		return nil, 0, err
	}
	productIDs = util.Unique(productIDs)
	productItemMap, err := c.dao.ProductItemDAO.MGetByProductIDs(c.ctx, productIDs)
	if err != nil {
		hlog.CtxErrorf(c.ctx, "MGetByProductIDs error: %v", err)
		return nil, 0, err
	}

	productSpecMap, err := c.dao.ProductSpecDAO.MGetByProductIDs(c.ctx, productIDs)
	if err != nil {
		hlog.CtxErrorf(c.ctx, "ProductSpecDAO.MGetByProductIDs error: %v", err)
		return nil, 0, err
	}

	productSpecValueMap, err := c.dao.ProductSpecValueDAO.MGetByProductIDs(c.ctx, productIDs)
	if err != nil {
		hlog.CtxErrorf(c.ctx, "ProductSpecValueDAO.MGetByProductIDs error: %v", err)
		return nil, 0, err
	}

	return pack.CartList(list, productMap, productItemMap, productSpecMap, productSpecValueMap), total, nil
}

func (c *CartService) AddCart(req *cart.AddCartRequest) error {
	cartInfo, err := c.dao.CartDAO.GetByConditions(c.ctx, []gen.Condition{
		dal.Cart.UserID.Eq(c.common.GetUserInfo().ID),
		dal.Cart.BizID.Eq(config.Values.BizID),
		dal.Cart.ProductID.Eq(req.ProductID),
		dal.Cart.SkuID.Eq(req.GetSKUID()),
	})
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		hlog.CtxErrorf(c.ctx, "GetCartByConditions error: %v", err)
		return err
	}
	if err == nil {
		if err = c.UpdateCart(&cart.UpdateCartRequest{
			ID:     cartInfo.ID,
			Number: cartInfo.Number + req.Number,
		}); err != nil {
			hlog.CtxErrorf(c.ctx, "UpdateCart error: %v", err)
			return err
		}
	} else {
		data := &model.Cart{
			ProductID: req.GetProductID(),
			Number:    req.Number,
			BizID:     config.Values.BizID,
			UserID:    c.common.GetUserInfo().ID,
			SkuID:     req.SKUID,
		}
		if _, err = c.dao.CartDAO.Create(c.ctx, data); err != nil {
			hlog.CtxErrorf(c.ctx, "AddCart error: %v", err)
			return err
		}
	}
	return nil
}

func (c *CartService) UpdateCart(req *cart.UpdateCartRequest) error {
	if err := c.dao.CartDAO.Update(c.ctx,
		[]gen.Condition{dal.Cart.ID.Eq(req.ID)},
		[]field.AssignExpr{dal.Cart.Number.Value(req.Number)}); err != nil {
		hlog.CtxErrorf(c.ctx, "UpdateCart error: %v", err)
		return err
	}
	return nil
}

func (c *CartService) DeleteCart(req *cart.DeleteCartRequest) error {
	if err := c.dao.CartDAO.Delete(c.ctx, []gen.Condition{
		dal.Cart.ID.In(req.GetIDs()...),
	}); err != nil {
		hlog.CtxErrorf(c.ctx, "DeleteCart error: %v", err)
		return err
	}
	return nil
}

func (c *CartService) GetCartTotal(req *cart.GetCartTotalRequest) (int64, error) {
	total, err := c.dao.CartDAO.GetTotal(c.ctx, []gen.Condition{
		dal.Cart.UserID.Eq(c.common.GetUserInfo().ID),
	})
	if err != nil {
		hlog.CtxErrorf(c.ctx, "GetCartTotal error: %v", err)
		return 0, err
	}
	return total, nil
}
